#include <sstream>
#include <string>

#include <libtcod/libtcod.hpp>

#include "Databank.hpp"
#include "ItemManager.hpp"
#include "Log.hpp"
#include "Material.hpp"
#include "Player.hpp"
#include "TurnSchedule.hpp"

#include "Game.hpp"

std::vector<Actor*> Game::Actors;
bool Game::Running = true;
Town* Game::Area;

int Game::run()
{
	Log::init("log");

	Databank::load();
	Material::load();

	TCODConsole::setCustomFont("data/terminal8x8_aa_ro.png", TCOD_FONT_LAYOUT_ASCII_INROW);
	TCODConsole::initRoot(80, 50, "Stone and Steel", false);
	TCODConsole::root->setKeyboardRepeat(250, 50);

	gPlayer = new Player(GetPlayerName(), GetPlayerRace());
	gPlayer->setPosition(Vector2d(50, 50));

	//Area = new Dungeon();
	//Area->generate("Halls of Testing", 5, 100, 100, EGA_BSP);
	Area = new Town();
	Area->generate("Town of Testing");

	gPlayer->setZone(Area);

	render(gPlayer->getShape(), gPlayer->getPosition(), gPlayer->getSight());

	while (Running)
	{
		TurnSchedule::run();
		Area->update();
		
		render(gPlayer->getShape(), gPlayer->getPosition(), gPlayer->getSight());
	}
	TCODConsole::root->print(3, 3, "Quitting...");
	TCODConsole::root->flush();

	TurnSchedule::clear();

	Actors.clear();
	
	delete gPlayer;
	delete Area;

	return 0;
}

Town* Game::getDungeon()
{
	return Area;
}

void Game::quit()
{
	Running = false;
}

void Game::render(char centerShape, Vector2d center, unsigned int sight, bool lookmode)
{
	TCODConsole::root->clear();

	if (lookmode)
		Area->getViewMap()->computeFov(gPlayer->getPosition().X, gPlayer->getPosition().Y, sight);
	else
		Area->getViewMap()->computeFov(center.X, center.Y, sight);

	int i = 0, j = 0;
	for (int x = center.X-40; x < center.X+40; ++x)
	{
		for (int y = center.Y-25; y < center.Y+25; ++y)
		{
			Tile* tile = Area->getTile(Vector2d(x, y));
			if (tile != NULL)
			{
				ItemVector items = tile->getItems();
				if (Area->getViewMap()->isInFov(x, y))
				{
					if (items.size() > 1)
						TCODConsole::root->putCharEx(i, j, items.back()->getShape(), items.back()->getForeColor(), TCODColor::amber);
					else
						TCODConsole::root->putCharEx(i, j, items.back()->getShape(), items.back()->getForeColor(), items.back()->getBackColor());

					if (!tile->hasSeen())
						tile->setSeen(true);

					for (unsigned int n = 0; n < Game::Actors.size(); ++n)
						if (Actors[n]->getPosition() == Vector2d(x, y))
							TCODConsole::root->putChar(i, j, Game::Actors[n]->getShape());
					
					if (lookmode && gPlayer->getPosition() == Vector2d(x, y))
						TCODConsole::root->putCharEx(i, j, gPlayer->getShape(), gPlayer->getForeColor(), gPlayer->getBackColor());
				}
				else
					if (tile->hasSeen())
						TCODConsole::root->putCharEx(i, j, items.back()->getShape(), items.back()->getForeColor(), TCODColor::darkestBlue);
			}
			++j;
		}
		j = 0;
		++i;
	}

	TCODConsole::root->putChar(40, 25, centerShape);
	TCODConsole::root->flush();
}

char Game::GetPlayerRace()
{
	TCODConsole::root->clear();
	TCODConsole::root->print(3, 5, "What race were you born into? ");

	unsigned int i = 1;
	for (std::map<unsigned int, RaceData>::iterator itr = Databank::Race.begin(); itr != Databank::Race.end(); ++itr)
	{
		std::stringstream stream;
		stream << "(" << (*itr).second.Key << ") " << (*itr).second.Name;
		TCODConsole::root->print(3, 5+i, stream.str().c_str());
		++i;
	}

	TCODConsole::root->flush();
	
	while (true)
	{
		TCOD_key_t key = TCODConsole::waitForKeypress(false);
		if (key.vk != TCODK_SHIFT && key.vk != TCODK_ENTER && key.vk != TCODK_BACKSPACE)
			for (std::map<unsigned int, RaceData>::iterator itr = Databank::Race.begin(); itr != Databank::Race.end(); ++itr)
				if (key.c == (*itr).second.Key)
					return (*itr).first;
	}
}

std::string Game::GetPlayerName()
{
	std::string name;
	std::string prompt = "What is your name? ";

	TCODConsole::root->clear();
	TCODConsole::root->print(3, 5, prompt.c_str());
	TCODConsole::root->flush();

	while (true)
	{
		TCOD_key_t key = TCODConsole::waitForKeypress(false);
		if (key.vk == TCODK_ENTER && name.size() > 0)
			break;
		else if (key.vk != TCODK_SHIFT && key.vk != TCODK_ENTER && key.vk != TCODK_BACKSPACE)
			name += key.c;
		else if (key.vk == TCODK_BACKSPACE && name.size() > 0)
			name.erase(name.end()-1);

		TCODConsole::root->clear();
		TCODConsole::root->print(3, 5, prompt.c_str());
		TCODConsole::root->print(3+prompt.size(), 5, name.c_str());
		TCODConsole::root->flush();
	}

	return name;
}

